function SM4Util(secretKey) {
		let base64js = require("./base64.js")
		this.secretKey = secretKey;
		this.iv = "";
		this.decryptData_ECB = function(data) {
			var byteEcb = base64js.toByteArray(data)
			// 字符串转换成byte
			var key = this.stringToByte(this.secretKey);
			var sm4 = new SM4();
			// 进行sm
			var plain = sm4.decrypt_ecb(key, byteEcb);

			// 这里可以不转字符串可以转16进制 方法为Hex.encode
			return Hex.bytesToUtf8Str(plain);
		}

		// 返回字符串
		this.encryptData_ECB = function(data) {

			var inputBytes = this.stringToByte(data);
			var key = this.stringToByte(this.secretKey);
			var sm4 = new SM4();
			var cipher = sm4.encrypt_ecb(key, inputBytes);
			// byte流转base字符串。
			var cipherText = base64js.fromByteArray(cipher);
			if (cipherText != null && cipherText.trim().length > 0) {
				cipherText.replace(/(\s*|\t|\r|\n)/g, "");
			}
			return cipherText;
		}

		// 返回字符串
		this.decryptData_CBC = function(data) {
			var inputBytes = base64js.toByteArray(data);
			var key = this.stringToByte(this.secretKey);
			var iv = this.stringToByte(this.iv);
			var sm4 = new SM4();
			var plain = sm4.decrypt_cbc(key, iv, inputBytes);
			// 这里可以不转字符串可以转16进制 方法为Hex.encode
			return Hex.bytesToUtf8Str(plain);
		}

		// 返回字符串
		this.encryptData_CBC = function(data) {
			var inputBytes = this.stringToByte(data);
			var key = this.stringToByte(this.secretKey);
			var iv = this.stringToByte(this.iv);
			var sm4 = new SM4();
			var cipher = sm4.encrypt_cbc(key, iv, inputBytes);
			// byte流转base字符串。
			var cipherText = base64js.fromByteArray(cipher);
			if (cipherText != null && cipherText.trim().length > 0) {
				cipherText.replace(/(\s*|\t|\r|\n)/g, "");
			}
			return cipherText;
		}


		this.stringToByte = function(str) {
			var bytes = new Array();
			var len, c;
			len = str.length;
			for (var i = 0; i < len; i++) {
				c = str.charCodeAt(i);
				if (c >= 0x010000 && c <= 0x10FFFF) {
					bytes.push(((c >> 18) & 0x07) | 0xF0);
					bytes.push(((c >> 12) & 0x3F) | 0x80);
					bytes.push(((c >> 6) & 0x3F) | 0x80);
					bytes.push((c & 0x3F) | 0x80);
				} else if (c >= 0x000800 && c <= 0x00FFFF) {
					bytes.push(((c >> 12) & 0x0F) | 0xE0);
					bytes.push(((c >> 6) & 0x3F) | 0x80);
					bytes.push((c & 0x3F) | 0x80);
				} else if (c >= 0x000080 && c <= 0x0007FF) {
					bytes.push(((c >> 6) & 0x1F) | 0xC0);
					bytes.push((c & 0x3F) | 0x80);
				} else {
					bytes.push(c & 0xFF);
				}
			}
			return bytes;
		}

	}

	function SM4() {

		this.sbox = new Array(
			0xd6, 0x90, 0xe9, 0xfe, 0xcc, 0xe1, 0x3d, 0xb7, 0x16, 0xb6, 0x14, 0xc2, 0x28, 0xfb, 0x2c, 0x05,
			0x2b, 0x67, 0x9a, 0x76, 0x2a, 0xbe, 0x04, 0xc3, 0xaa, 0x44, 0x13, 0x26, 0x49, 0x86, 0x06, 0x99,
			0x9c, 0x42, 0x50, 0xf4, 0x91, 0xef, 0x98, 0x7a, 0x33, 0x54, 0x0b, 0x43, 0xed, 0xcf, 0xac, 0x62,
			0xe4, 0xb3, 0x1c, 0xa9, 0xc9, 0x08, 0xe8, 0x95, 0x80, 0xdf, 0x94, 0xfa, 0x75, 0x8f, 0x3f, 0xa6,
			0x47, 0x07, 0xa7, 0xfc, 0xf3, 0x73, 0x17, 0xba, 0x83, 0x59, 0x3c, 0x19, 0xe6, 0x85, 0x4f, 0xa8,
			0x68, 0x6b, 0x81, 0xb2, 0x71, 0x64, 0xda, 0x8b, 0xf8, 0xeb, 0x0f, 0x4b, 0x70, 0x56, 0x9d, 0x35,
			0x1e, 0x24, 0x0e, 0x5e, 0x63, 0x58, 0xd1, 0xa2, 0x25, 0x22, 0x7c, 0x3b, 0x01, 0x21, 0x78, 0x87,
			0xd4, 0x00, 0x46, 0x57, 0x9f, 0xd3, 0x27, 0x52, 0x4c, 0x36, 0x02, 0xe7, 0xa0, 0xc4, 0xc8, 0x9e,
			0xea, 0xbf, 0x8a, 0xd2, 0x40, 0xc7, 0x38, 0xb5, 0xa3, 0xf7, 0xf2, 0xce, 0xf9, 0x61, 0x15, 0xa1,
			0xe0, 0xae, 0x5d, 0xa4, 0x9b, 0x34, 0x1a, 0x55, 0xad, 0x93, 0x32, 0x30, 0xf5, 0x8c, 0xb1, 0xe3,
			0x1d, 0xf6, 0xe2, 0x2e, 0x82, 0x66, 0xca, 0x60, 0xc0, 0x29, 0x23, 0xab, 0x0d, 0x53, 0x4e, 0x6f,
			0xd5, 0xdb, 0x37, 0x45, 0xde, 0xfd, 0x8e, 0x2f, 0x03, 0xff, 0x6a, 0x72, 0x6d, 0x6c, 0x5b, 0x51,
			0x8d, 0x1b, 0xaf, 0x92, 0xbb, 0xdd, 0xbc, 0x7f, 0x11, 0xd9, 0x5c, 0x41, 0x1f, 0x10, 0x5a, 0xd8,
			0x0a, 0xc1, 0x31, 0x88, 0xa5, 0xcd, 0x7b, 0xbd, 0x2d, 0x74, 0xd0, 0x12, 0xb8, 0xe5, 0xb4, 0xb0,
			0x89, 0x69, 0x97, 0x4a, 0x0c, 0x96, 0x77, 0x7e, 0x65, 0xb9, 0xf1, 0x09, 0xc5, 0x6e, 0xc6, 0x84,
			0x18, 0xf0, 0x7d, 0xec, 0x3a, 0xdc, 0x4d, 0x20, 0x79, 0xee, 0x5f, 0x3e, 0xd7, 0xcb, 0x39, 0x48
		);

		this.fk = new Array(0xa3b1bac6, 0x56aa3350, 0x677d9197, 0xb27022dc);
		this.ck = new Array(
			0x00070e15, 0x1c232a31, 0x383f464d, 0x545b6269,
			0x70777e85, 0x8c939aa1, 0xa8afb6bd, 0xc4cbd2d9,
			0xe0e7eef5, 0xfc030a11, 0x181f262d, 0x343b4249,
			0x50575e65, 0x6c737a81, 0x888f969d, 0xa4abb2b9,
			0xc0c7ced5, 0xdce3eaf1, 0xf8ff060d, 0x141b2229,
			0x30373e45, 0x4c535a61, 0x686f767d, 0x848b9299,
			0xa0a7aeb5, 0xbcc3cad1, 0xd8dfe6ed, 0xf4fb0209,
			0x10171e25, 0x2c333a41, 0x484f565d, 0x646b7279
		);
	}

	SM4.prototype = {
		expandKey: function(key) {
			var k = new Array(36);
			var mk = byteArrayToIntArray(key);
			k[0] = mk[0] ^ this.fk[0];
			k[1] = mk[1] ^ this.fk[1];
			k[2] = mk[2] ^ this.fk[2];
			k[3] = mk[3] ^ this.fk[3];
			var rk = new Array(32);
			for (var i = 0; i < 32; i++) {
				k[(i + 4)] = (k[i] ^ this.T1(k[(i + 1)] ^ k[(i + 2)] ^ k[(i + 3)] ^ this.ck[i]));
				rk[i] = k[(i + 4)];
			}
			return rk;
		},
		T1: function(ta) {
			var rk = 0;
			var b = new Array(4);
			var a = intToByte(ta);
			b[0] = this.sbox[a[0] & 0xFF];
			b[1] = this.sbox[a[1] & 0xFF];
			b[2] = this.sbox[a[2] & 0xFF];
			b[3] = this.sbox[a[3] & 0xFF];
			var bint = byteToInt(b, 0);
			var rk = bint ^ (bint << 13 | (bint >>> (32 - 13))) ^ (bint << 23 | (bint >>> (32 - 23)));
			return rk;
		},
		one_encrypt: function(rk, data) {
			var x = new Array(36);
			x[0] = byteToInt(data, 0);
			x[1] = byteToInt(data, 4);
			x[2] = byteToInt(data, 8);
			x[3] = byteToInt(data, 12);
			for (var i = 0; i < 32; i++) {
				x[(i + 4)] = x[i] ^ this.T0(x[(i + 1)] ^ x[(i + 2)] ^ x[(i + 3)] ^ rk[i]);
			}
			var tmpx = new Array(4);
			for (var i = 35; i >= 32; i--) {
				tmpx[35 - i] = x[i];
			}
			var xbyte = intArrayToByteArray(tmpx);

			return xbyte;
		},
		T0: function(ta) {
			var a = intToByte(ta);
			var b = new Array(4);
			b[0] = this.sbox[a[0] & 0xFF];
			b[1] = this.sbox[a[1] & 0xFF];
			b[2] = this.sbox[a[2] & 0xFF];
			b[3] = this.sbox[a[3] & 0xFF];
			var bint = byteToInt(b, 0);
			var c = bint ^ (bint << 2 | (bint >>> (32 - 2))) ^ (bint << 10 | (bint >>> (32 - 10))) ^ (
				bint << 18 | (
					bint >>> (32 - 18))) ^ (bint << 24 | (bint >>> (32 - 24)));
			return c;
		},
		pkcs7padding: function(input, mode) {
			if (input == null) {
				return null;
			}

			var ret = null;
			if (mode == 1) //填充
			{
				var p = 16 - input.length % 16;
				ret = new Array(input.length + p);
				arrayCopy(input, 0, ret, 0, input.length);
				for (var i = 0; i < p; i++) {
					ret[input.length + i] = p;
				}
			} else //去除填充
			{
				var p = input[input.length - 1];
				ret = new Array(input.length - p);
				arrayCopy(input, 0, ret, 0, input.length - p);
			}
			return ret;
		},
		encrypt_ecb: function(key, data) {
			if (key == undefined || key == null || key.length % 16 != 0) {
				return null;
			}
			if (data == undefined || data == null || data.length <= 0) {
				return null;
			}
			var rk = this.expandKey(key);
			var blockLen = 16;
			var loop = parseInt(data.length / blockLen); //注意不能整除会有小数，要取整
			var cipher = new Array((loop + 1) * blockLen);
			var tmp = new Array(blockLen);
			var oneCipher = null;

			for (var i = 0; i < loop; i++) {
				arrayCopy(data, i * blockLen, tmp, 0, blockLen);
				oneCipher = this.one_encrypt(rk, tmp);
				arrayCopy(oneCipher, 0, cipher, i * blockLen, blockLen);
			}

			var lessData = new Array(data.length % blockLen);
			if (lessData.length > 0) {
				arrayCopy(data, loop * blockLen, lessData, 0, data.length % blockLen);
			}
			var padding = this.pkcs7padding(lessData, 1);
			oneCipher = this.one_encrypt(rk, padding);
			arrayCopy(oneCipher, 0, cipher, loop * blockLen, blockLen);

			return cipher;
		},
		decrypt_ecb: function(key, data) {
			if (key == undefined || key == null || key.length % 16 != 0) {
				return null;
			}
			if (data == undefined || data == null || data.length % 16 != 0) {
				return null;
			}
			var rk = this.expandKey(key);
			var nrk = new Array(32);
			for (var i = 0; i < rk.length; i++) {
				nrk[i] = rk[32 - i - 1];
			}
			var blockLen = 16;
			var loop = data.length / blockLen - 1;
			var tmp = new Array(blockLen);
			var onePlain = null;
			var plain = null;
			//先解密最后一部分，确定数据长度
			arrayCopy(data, loop * blockLen, tmp, 0, blockLen);
			onePlain = this.one_encrypt(nrk, tmp);
			var lastPart = this.pkcs7padding(onePlain, 0);

			plain = new Array(loop * blockLen + lastPart.length);
			arrayCopy(lastPart, 0, plain, loop * blockLen, lastPart.length);

			//解密剩下部分数据
			for (var i = 0; i < loop; i++) {
				arrayCopy(data, i * blockLen, tmp, 0, blockLen);
				onePlain = this.one_encrypt(nrk, tmp);
				arrayCopy(onePlain, 0, plain, i * blockLen, blockLen);
			}

			return plain;
		},
		encrypt_cbc: function(key, iv, data) {
			if (key == undefined || key == null || key.length % 16 != 0) {
				return null;
			}
			if (data == undefined || data == null || data.length <= 0) {
				return null;
			}
			if (iv == undefined || iv == null || iv.length % 16 != 0) {
				return null;
			}
			var rk = this.expandKey(key);
			var blockLen = 16;
			var loop = parseInt(data.length / blockLen); //注意不能整除会有小数，要取整
			var cipher = new Array((loop + 1) * blockLen);
			var tmp = new Array(blockLen);

			for (var i = 0; i < loop; i++) {
				arrayCopy(data, i * blockLen, tmp, 0, blockLen);
				for (var j = 0; j < blockLen; j++) {
					tmp[j] = tmp[j] ^ iv[j];
				}
				iv = this.one_encrypt(rk, tmp);
				arrayCopy(iv, 0, cipher, i * blockLen, blockLen);
			}

			var lessData = new Array(data.length % blockLen);
			if (lessData.length > 0) {
				arrayCopy(data, loop * blockLen, lessData, 0, data.length % blockLen);
			}
			var padding = this.pkcs7padding(lessData, 1);
			for (var i = 0; i < blockLen; i++) {
				padding[i] = padding[i] ^ iv[i];
			}
			iv = this.one_encrypt(rk, padding);
			arrayCopy(iv, 0, cipher, loop * blockLen, blockLen);

			return cipher;
		},
		decrypt_cbc: function(key, iv, data) {
			if (key == undefined || key == null || key.length % 16 != 0) {
				return null;
			}
			if (data == undefined || data == null || data.length % 16 != 0) {
				return null;
			}
			if (iv == undefined || iv == null || iv.length % 16 != 0) {
				return null;
			}
			var rk = this.expandKey(key);
			var nrk = new Array(32);
			for (var i = 0; i < rk.length; i++) {
				nrk[i] = rk[32 - i - 1];
			}
			var blockLen = 16;
			var loop = data.length / blockLen;
			var tmp = new Array(blockLen);
			var onePlain = null;
			var plain = null;


			//解密
			plain = new Array(data.length);
			for (var i = 0; i < loop; i++) {
				arrayCopy(data, i * blockLen, tmp, 0, blockLen);
				onePlain = this.one_encrypt(nrk, tmp);
				for (var j = 0; j < blockLen; j++) {
					onePlain[j] = onePlain[j] ^ iv[j];
				}
				arrayCopy(tmp, 0, iv, 0, blockLen);
				arrayCopy(onePlain, 0, plain, i * blockLen, blockLen);
			}

			//去填充，确定数据长度
			var lastPart = this.pkcs7padding(onePlain, 0);

			var realPlain = new Array(plain.length - blockLen + lastPart.length);
			arrayCopy(plain, 0, realPlain, 0, plain.length - blockLen);
			arrayCopy(lastPart, 0, realPlain, plain.length - blockLen, lastPart.length);

			return realPlain;
		}
	}

	function Hex() {

	}

	Hex.encode = function(b, pos, len) {
		var hexCh = new Array(len * 2);
		var hexCode = new Array('0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E',
			'F');

		for (var i = pos, j = 0; i < len + pos; i++, j++) {
			hexCh[j] = hexCode[(b[i] & 0xFF) >> 4];
			hexCh[++j] = hexCode[(b[i] & 0x0F)];
		}

		return hexCh.join('');
	}

	Hex.decode = function(hex) {

		if (hex == null || hex == '') {
			return null;
		}
		if (hex.length % 2 != 0) {
			return null;
		}

		var ascLen = hex.length / 2;
		var hexCh = this.toCharCodeArray(hex);
		var asc = new Array(ascLen);

		for (var i = 0; i < ascLen; i++) {

			if (hexCh[2 * i] >= 0x30 && hexCh[2 * i] <= 0x39) {
				asc[i] = ((hexCh[2 * i] - 0x30) << 4);
			} else if (hexCh[2 * i] >= 0x41 && hexCh[2 * i] <= 0x46) { //A-F : 0x41-0x46
				asc[i] = ((hexCh[2 * i] - 0x41 + 10) << 4);
			} else if (hexCh[2 * i] >= 0x61 && hexCh[2 * i] <= 0x66) { //a-f  : 0x61-0x66
				asc[i] = ((hexCh[2 * i] - 0x61 + 10) << 4);
			} else {
				return null;
			}

			if (hexCh[2 * i + 1] >= 0x30 && hexCh[2 * i + 1] <= 0x39) {
				asc[i] = (asc[i] | (hexCh[2 * i + 1] - 0x30));
			} else if (hexCh[2 * i + 1] >= 0x41 && hexCh[2 * i + 1] <= 0x46) {
				asc[i] = (asc[i] | (hexCh[2 * i + 1] - 0x41 + 10));
			} else if (hexCh[2 * i + 1] >= 0x61 && hexCh[2 * i + 1] <= 0x66) {
				asc[i] = (asc[i] | (hexCh[2 * i + 1] - 0x61 + 10));
			} else {
				return null;
			}
		}
		return asc;
	}

	Hex.utf8StrToHex = function(utf8Str) {
		var ens = encodeURIComponent(utf8Str);
		var es = unescape(ens);
		var esLen = es.length;

		// Convert
		var words = [];
		for (var i = 0; i < esLen; i++) {
			words[i] = (es.charCodeAt(i).toString(16));
		}
		return words.join('');
	}

	Hex.utf8StrToBytes = function(utf8Str) {
		var ens = encodeURIComponent(utf8Str);
		var es = unescape(ens);
		var esLen = es.length;

		// Convert
		var words = [];
		for (var i = 0; i < esLen; i++) {
			words[i] = es.charCodeAt(i);
		}
		return words;
	}

	Hex.hexToUtf8Str = function(utf8Str) {
		var utf8Byte = Hex.decode(utf8Str);
		var latin1Chars = [];
		for (var i = 0; i < utf8Byte.length; i++) {
			latin1Chars.push(String.fromCharCode(utf8Byte[i]));
		}
		return decodeURIComponent(escape(latin1Chars.join('')));
	}

	Hex.bytesToUtf8Str = function(bytesArray) {
		var utf8Byte = bytesArray;
		var latin1Chars = [];
		for (var i = 0; i < utf8Byte.length; i++) {
			latin1Chars.push(String.fromCharCode(utf8Byte[i]));
		}
		return decodeURIComponent(escape(latin1Chars.join('')));
	}

	Hex.toCharCodeArray = function(chs) {
		var chArr = new Array(chs.length);
		for (var i = 0; i < chs.length; i++) {
			chArr[i] = chs.charCodeAt(i);
		}
		return chArr;
	}
	/*
	 *
	 * 字节流转换工具js
	 *
	 */

	/*
	 * 数组复制
	 */
	function arrayCopy(src, pos1, dest, pos2, len) {
		var realLen = len;
		if (pos1 + len > src.length && pos2 + len <= dest.length) {
			realLen = src.length - pos1;
		} else if (pos2 + len > dest.length && pos1 + len <= src.length) {
			realLen = dest.length - pos2;
		} else if (pos1 + len <= src.length && pos2 + len <= dest.length) {
			realLen = len;
		} else if (dest.length < src.length) {
			realLen = dest.length - pos2;
		} else {
			realLen = src.length - pos2;
		}

		for (var i = 0; i < realLen; i++) {
			dest[i + pos2] = src[i + pos1];
		}
	}

	/*
	 * 长整型转成字节，一个长整型为8字节
	 * 返回：字节数组
	 */
	function longToByte(num) {
		//TODO 这里目前只转换了低四字节，因为js没有长整型，得要封装
		return new Array(
			0,
			0,
			0,
			0,
			(num >> 24) & 0x000000FF,
			(num >> 16) & 0x000000FF,
			(num >> 8) & 0x000000FF,
			(num) & 0x000000FF
		);
	}

	/*
	 * int数转成byte数组
	 * 事实上只不过转成byte大小的数，实际占用空间还是4字节
	 * 返回：字节数组
	 */
	function intToByte(num) {
		return new Array(
			(num >> 24) & 0x000000FF,
			(num >> 16) & 0x000000FF,
			(num >> 8) & 0x000000FF,
			(num) & 0x000000FF
		);
	}

	/*
	 * int数组转成byte数组，一个int数值转成四个byte
	 * 返回:byte数组
	 */
	function intArrayToByteArray(nums) {
		var b = new Array(nums.length * 4);

		for (var i = 0; i < nums.length; i++) {
			arrayCopy(intToByte(nums[i]), 0, b, i * 4, 4);
		}

		return b;
	}

	/*
	 * byte数组转成int数值
	 * 返回：int数值
	 */
	function byteToInt(b, pos) {
		if (pos + 3 < b.length) {
			return ((b[pos]) << 24) | ((b[pos + 1]) << 16) | ((b[pos + 2]) << 8) | ((b[pos + 3]));
		} else if (pos + 2 < b.length) {
			return ((b[pos + 1]) << 16) | ((b[pos + 2]) << 8) | ((b[pos + 3]));
		} else if (pos + 1 < b.length) {
			return ((b[pos]) << 8) | ((b[pos + 1]));
		} else {
			return ((b[pos]));
		}
	}

	/*
	 * byte数组转成int数组,每四个字节转成一个int数值
	 *
	 */
	function byteArrayToIntArray(b) {
		// var arrLen = b.length%4==0 ? b.length/4:b.length/4+1;
		var arrLen = Math.ceil(b.length / 4); //向上取整
		var out = new Array(arrLen);
		for (var i = 0; i < b.length; i++) {
			b[i] = b[i] & 0xFF; //避免负数造成影响
		}
		for (var i = 0; i < out.length; i++) {
			out[i] = byteToInt(b, i * 4);
		}
		return out;
	}
export default SM4Util